package com.alibaba.csp.sentinel.dashboard.rule.redis;

import java.time.Duration;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.AbstractDynamicRuleProviderAndPublisher;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleConstants;
import com.alibaba.csp.sentinel.datasource.redis.config.RedisConnectionConfig;
import com.alibaba.csp.sentinel.util.StringUtil;

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;

/**
* @Description: TODO
* @author blueice
* @date 2021年3月25日 上午11:39:57
*
*/
@Configuration
@ConfigurationProperties(prefix="sentinel.datasource.redis")
public class RedisConfig
{
    private String serverAddr = "localhost";
    private int serverPort = 6379;
    private int database = 0;
    private String password = "";
    
    @Bean
    public RedisClient redisClient() throws Exception {
        RedisConnectionConfig redisConnectionConfig = RedisConnectionConfig.builder().withHost(serverAddr)
        .withPort(serverPort).withPassword(password).withDatabase(database).build();
        return getRedisStandaloneClient(redisConnectionConfig);
    }
    
    private RedisClient getRedisStandaloneClient(RedisConnectionConfig connectionConfig) {
        char[] password = connectionConfig.getPassword();
        String clientName = connectionConfig.getClientName();
        RedisURI.Builder redisUriBuilder = RedisURI.builder();
        redisUriBuilder.withHost(connectionConfig.getHost())
            .withPort(connectionConfig.getPort())
            .withDatabase(connectionConfig.getDatabase())
            .withTimeout(Duration.ofMillis(connectionConfig.getTimeout()));
        if (password != null) {
            redisUriBuilder.withPassword(connectionConfig.getPassword());
        }
        if (StringUtil.isNotEmpty(connectionConfig.getClientName())) {
            redisUriBuilder.withClientName(clientName);
        }
        return RedisClient.create(redisUriBuilder.build());
    }
    
    @Bean
    @ConditionalOnProperty(prefix=DynamicRuleConstants.PROPERTY_PREFIX, 
        name=DynamicRuleConstants.AUTHORITY_STORE, havingValue=DynamicRuleConstants.SUPPORT_REDIS)
    public AbstractDynamicRuleProviderAndPublisher<AuthorityRuleEntity> authorityRuleProviderAndPublisher() {
        return new AbstractRedisRuleProviderAndPublisher<AuthorityRuleEntity>() {
            @Override
            protected String ruleSuffix()
            {
                return DynamicRuleConstants.AUTHORITY_DATA_ID_POSTFIX;
            }
        };
    }
    
    @Bean
    @ConditionalOnProperty(prefix=DynamicRuleConstants.PROPERTY_PREFIX, 
        name=DynamicRuleConstants.DEGRADE_STORE, havingValue=DynamicRuleConstants.SUPPORT_REDIS)
    public AbstractDynamicRuleProviderAndPublisher<DegradeRuleEntity> degradeRuleProviderAndPublisher() {
        return new AbstractRedisRuleProviderAndPublisher<DegradeRuleEntity>() {
            @Override
            protected String ruleSuffix()
            {
                return DynamicRuleConstants.DEGRADE_DATA_ID_POSTFIX;
            }
        };
    }
    
    @Bean
    @ConditionalOnProperty(prefix=DynamicRuleConstants.PROPERTY_PREFIX, 
        name=DynamicRuleConstants.FLOW_STORE, havingValue=DynamicRuleConstants.SUPPORT_REDIS)
    public AbstractDynamicRuleProviderAndPublisher<FlowRuleEntity> flowRuleProviderAndPublisher() {
        return new AbstractRedisRuleProviderAndPublisher<FlowRuleEntity>() {
            @Override
            protected String ruleSuffix()
            {
                return DynamicRuleConstants.FLOW_DATA_ID_POSTFIX;
            }
        };
    }
    
    @Bean
    @ConditionalOnProperty(prefix=DynamicRuleConstants.PROPERTY_PREFIX, 
        name=DynamicRuleConstants.PARAM_STORE, havingValue=DynamicRuleConstants.SUPPORT_REDIS)
    public AbstractDynamicRuleProviderAndPublisher<ParamFlowRuleEntity> paramRuleProviderAndPublisher() {
        return new AbstractRedisRuleProviderAndPublisher<ParamFlowRuleEntity>() {
            @Override
            protected String ruleSuffix()
            {
                return DynamicRuleConstants.PARAM_FLOW_DATA_ID_POSTFIX;
            }
        };
    }
    
    @Bean
    @ConditionalOnProperty(prefix=DynamicRuleConstants.PROPERTY_PREFIX, 
        name=DynamicRuleConstants.SYSTEM_STORE, havingValue=DynamicRuleConstants.SUPPORT_REDIS)
    public AbstractDynamicRuleProviderAndPublisher<SystemRuleEntity> systemRuleProviderAndPublisher() {
        return new AbstractRedisRuleProviderAndPublisher<SystemRuleEntity>() {
            @Override
            protected String ruleSuffix()
            {
                return DynamicRuleConstants.SYSTEM_DATA_ID_POSTFIX;
            }
        };
    }
    
    public String getServerAddr()
    {
        return serverAddr;
    }

    public void setServerAddr(String serverAddr)
    {
        this.serverAddr = serverAddr;
    }

    public int getServerPort()
    {
        return serverPort;
    }

    public void setServerPort(int serverPort)
    {
        this.serverPort = serverPort;
    }

    public int getDatabase()
    {
        return database;
    }

    public void setDatabase(int database)
    {
        this.database = database;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
